﻿using BLL;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using static System.Net.Mime.MediaTypeNames;

namespace socketForm
{
    public partial class FrmServer : UIForm
    {   //建立通信
        Socket socket = null;
        List <Socket> clientProxySocketList = new List<Socket>();
        // 上一个页面
        private FrmConfig returnForm;
        // 定时器
        private System.Timers.Timer tmr = new System.Timers.Timer();
        public FrmServer(FrmConfig returnForm)
        {
            InitializeComponent();
            this.returnForm = returnForm;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 读取配置
            this.readConfig();
            // 定时器配置
            tmr.Elapsed += async (senderd, ee) => await AsyncMethodCallback(senderd);
            tmr.Interval = SqlConfig.stopTime;
            tmr.AutoReset = true; //true-一直循环 ，false-循环一次
            // tmr.SynchronizingObject = this; //运行在主线程上
            tmr.Enabled = false;
        }

        private void but_start_socket_Click(object sender, EventArgs e)
        {
            //1、创建socket
            socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            //2、绑定端口IP
            socket.Bind(new IPEndPoint(IPAddress.Parse(this.txtIP.Text), int.Parse(this.txtPort.Text)));
            //3、开始监听
            socket.Listen(10);//等待连接队列，同时来了100个连接请求，只能处理一个连接，队列里边放10个等待的连接，其他的返回错误消息
            //4、开始接受客户端连接
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptClientConnect),socket);
            // 启动禁用
            this.but_start_socket.Enabled = false;
            this.but_stop_socket.Enabled= true;
            //5、保存配置
            this.saveIni();
            //6、加入日志
            WriteLogPublic.WriteLogFunStr("启动Sorcke");
        }

        private void saveIni() {
            // 保存配置
            IniFileHelper.Instance.WriteIniString(SqlConfig.tcpConfigSection, SqlConfig.tcpConfigIp, this.txtIP.Text);
            IniFileHelper.Instance.WriteIniString(SqlConfig.tcpConfigSection, SqlConfig.tcpConfigPort, this.txtPort.Text);
        }

        private void readConfig()
        {
            this.txtIP.Text = String.IsNullOrEmpty(IniFileHelper.Instance.GetIniString(SqlConfig.tcpConfigSection, SqlConfig.tcpConfigIp)) ?
                SocketUtil.getIP() : IniFileHelper.Instance.GetIniString(SqlConfig.tcpConfigSection, SqlConfig.tcpConfigIp);

            var tcpConfigPort = IniFileHelper.Instance.GetIniString(SqlConfig.tcpConfigSection, SqlConfig.tcpConfigPort);
            if (!String.IsNullOrEmpty(tcpConfigPort)) this.txtPort.Text = tcpConfigPort;
        }

        public void AcceptClientConnect(object socket)
        {
            var serverSocket = socket as Socket;
            this.AppendTextToTxtLog("服务器端开始接收客户端连接");
            while (true) {
                Socket proxySocket=null;
                try {
                    proxySocket = serverSocket.Accept();//阻塞当前线程，接收客户端的连接
                }
                catch (Exception ex) {
                    AppendTextToTxtLog("服务器监听失败，请重新开始");
                    WriteLogPublic.WriteLogFunStr($"服务器监听失败，请重新开始。异常信息：{ex.Message}");
                    return;
                }
 
                AppendTextToTxtLog(string.Format("客户端：{0}连接上了", proxySocket.RemoteEndPoint.ToString()));
                clientProxySocketList.Add(proxySocket);
                //不停的接收当前连接的客户端发送来的消息
                //ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), proxySocket);
                ThreadPool.QueueUserWorkItem(ReceiveData, proxySocket);//语法糖：可以简写
                //proxySocket.Receive();//阻塞当前线程，需要开一个线程执行
            }
            
        }

        //接收客户端的消息
        public void ReceiveData(object socket)
        {
            byte[] data = new byte[1024 * 1024];
            var proxySocket = socket as Socket;
            while (true)
            {
                int len = 0;

                try
                {
                    len = proxySocket.Receive(data, 0, data.Length, SocketFlags.None);
                }
                catch(Exception ex)
                {
                    //客户端异常退出
                    AppendTextToTxtLog(string.Format("客户端：{0}非正常退出", proxySocket.RemoteEndPoint.ToString()));
                    WriteLogPublic.WriteLogFunStr($"客户端：{ex.Message}非正常退出");
                    clientProxySocketList.Remove(proxySocket);//客户端socket列表中移除
                    stopConnect(proxySocket);  //关闭连接
                    return; //让方法结束，结束当前接收数据的异步线程
                }


                //接收到0个字节代表客户端正常退出
                if (len<=0) 
                {
                    //客户端正常退出
                    AppendTextToTxtLog(string.Format("客户端：{0}正常退出", proxySocket.RemoteEndPoint.ToString()));
                    clientProxySocketList.Remove(proxySocket);//客户端socket列表中移除
                    stopConnect(proxySocket);  //关闭连接
                    return; //让方法结束，结束当前接收数据的异步线程
                }

                //把接收到的数据放到文本框上
                string str = Encoding.UTF8.GetString(data,0,len);
                AppendTextToTxtLog(string.Format("接收到客户端：{0}的消息：{1}",proxySocket.RemoteEndPoint.ToString(),str));
            }
        }

        private void stopConnect(Socket proxySocket)
        {
            try
            {
                if (proxySocket.Connected)
                {
                    proxySocket.Shutdown(SocketShutdown.Both);
                    proxySocket.Close(100);
                }
            }
            catch (Exception ex)
            {
                WriteLogPublic.WriteLogFunStr($"关闭连接：{ex.Message}");
            }
        }

        //往日志文本框上添加数据
        public void AppendTextToTxtLog(string txt)
        {
            if (txtLog.InvokeRequired) //判断是否跨线程访问
            {
                //Invoke同步方法      BeginInvoke异步方法
                txtLog.Invoke(new Action<string>(s => {
                    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                    WriteLogPublic.WriteLogFunStr(txt);
                }), txt);
            }
            else //本线程内访问
            {
                this.txtLog.Text = string.Format("{0}\r\n{1}", txt, txtLog.Text);
                WriteLogPublic.WriteLogFunStr(txt);
            }
            
        }

        /// <summary>
        /// 发送文字
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            if (clientProxySocketList.Count <= 0)
            {
                WriteLogPublic.WriteLogFunStr("手动-无链接");
                MessageBox.Show("无链接");
            }
            else {
                foreach (var proxySocket in clientProxySocketList)
                {
                    if (proxySocket.Connected)
                    {
                        byte[] data = Encoding.UTF8.GetBytes(txtMsg.Text);
                        //添加头部一个字节消息类型 : 1文字    2闪屏    3文件
                        byte[] result = new byte[data.Length + 1];
                        result[0] = 1;
                        Buffer.BlockCopy(data, 0, result, 1, data.Length);
                        proxySocket.Send(result, 0, result.Length, SocketFlags.None);
                    }
                }
            }
        }

        /// <summary>
        /// 发送闪屏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendShake_Click(object sender, EventArgs e)
        {
            foreach (var proxySocket in clientProxySocketList)
            {
                if (proxySocket.Connected)
                {
                    proxySocket.Send(new byte[]{2}, SocketFlags.None);
                }
            }
        }

        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            //读取要发送的文件数据
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() != DialogResult.OK) {
                    return;
                }
                //文件数据
                byte[] data = File.ReadAllBytes(ofd.FileName);
                //文件名数据：长度64
                byte[] nameData = new byte[64];
                byte[] temp = Encoding.UTF8.GetBytes(ofd.SafeFileName);
                Buffer.BlockCopy(temp, 0, nameData, 0, temp.Length);
                //数据包：1+64+文件数据字节数
                byte[] result = new byte[1+64+data.Length];
                result[0] = 3;
                Buffer.BlockCopy(nameData, 0, result, 1, nameData.Length);
                Buffer.BlockCopy(data, 0, result, 1+64, data.Length);
                string str = Encoding.UTF8.GetString(result);
                foreach (var proxySocket in clientProxySocketList)
                {
                    if (!proxySocket.Connected)
                    {
                        continue;
                    }
                    proxySocket.Send(result, SocketFlags.None);
                }
            }

        }

        private void FrmServer_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.returnForm.Visible = true;
        }

        private Task AsyncMethodCallback(object sender)
        {
            WriteInfo("tmr loop:  " + Thread.CurrentThread.ManagedThreadId);
            if (this.clientProxySocketList.Count <= 0) {
                WriteLogPublic.WriteLogFunStr("停止定时任务-无链接");
                // 停止定时任务
                this.stopTime(true);
            }
            else {
                lock (sender)
                {
                    // 清空重新记录
                    this.Invoke(new Action(() => {
                        txtSendInfo.Text = "";
                    }));
                    WriteInfo("tmr is running :" + Thread.CurrentThread.ManagedThreadId + "发送时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    TradSend tradSend = new TradSend(SqlConfig.sqlType, SqlConfig.sqlAddress, SqlConfig.sqlSelcet, SqlConfig.sqlSqlSort, SqlConfig.dataSize);
                    String sendStr = tradSend.findSendData();
                    WriteInfo("Count: " + Thread.CurrentThread.ManagedThreadId + "【" + sendStr + "】");
                    foreach (var proxySocket in clientProxySocketList)
                    {
                        if (proxySocket.Connected)
                        {
                            byte[] data = Encoding.UTF8.GetBytes(sendStr);
                            //添加头部一个字节消息类型 : 1文字    2闪屏    3文件
                            byte[] result = new byte[data.Length + 1];
                            result[0] = 1;
                            Buffer.BlockCopy(data, 0, result, 1, data.Length);
                            proxySocket.Send(result, 0, result.Length, SocketFlags.None);
                        }
                    }
                    // 删除日志
                    WriteLogPublic.DeleteLogFun();
                }
            }
            return Task.CompletedTask;
        }

        private void WriteInfo(string str)
        {
            if (txtSendInfo.InvokeRequired)
            {
                this.Invoke(new Action(() => { 
                    txtSendInfo.AppendText(str + "\r\n");
                    WriteLogPublic.WriteLogFunStr(str);
                }));
            }
            else
            {
                txtSendInfo.AppendText(str + "\r\n");
                WriteLogPublic.WriteLogFunStr(str);
            }
        }

        private void but_start_sendData_Click(object sender, EventArgs e)
        {
            if (this.clientProxySocketList.Count <= 0)
            {
                WriteLogPublic.WriteLogFunStr("启动失败！无TCP链接对象");
                MessageBox.Show("启动失败！无TCP链接对象");

            }
            else
            {
                WriteLogPublic.WriteLogFunStr("启动定时任务");
                this.startTime(false);
            }
        }

        private void but_stop_sendData_Click(object sender, EventArgs e)
        {
            WriteLogPublic.WriteLogFunStr("停止定时任务");
            // 停止任务
            this.stopTime(false);
        }

        private void frm_notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            //显示窗体
            this.Visible = true;
            //激活窗体并给予它焦点
            this.Activate();
            this.WindowState = FormWindowState.Normal;  // 恢复窗体正常大小
            //托盘区图标隐藏
            this.frm_notifyIcon.Visible = false;
        }

        private void FrmServer_Deactivate(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                //隐藏窗体
                this.Visible = false;
                //图标显示在托盘区
                this.frm_notifyIcon.Visible = true;
                this.frm_notifyIcon.ShowBalloonTip(2000, "提示", "双击图标恢复", ToolTipIcon.Info);
            }
        }

        private void but_stop_socket_Click(object sender, EventArgs e)
        {
            WriteLogPublic.WriteLogFunStr("关闭链接");
            if (socket != null)
            {
                socket.Close();
                // 启动禁用
                this.but_start_socket.Enabled = true;
                this.but_stop_socket.Enabled = false;
            }
            else
            {
                // 启动禁用
                this.but_start_socket.Enabled = true;
                this.but_stop_socket.Enabled = false;
            }
        }


        private void startTime(bool hasInvoke) {
            // 清理页面缓存数据
            System.Windows.Forms.Application.DoEvents();
            // 启动定时任务
            tmr.Start();
            if (hasInvoke)
            {
                this.Invoke(new Action(() =>
                {
                    this.but_start_sendData.Enabled = false;
                    this.but_stop_sendData.Enabled = true;
                }));
            }
            else {
                this.but_start_sendData.Enabled = false;
                this.but_stop_sendData.Enabled = true;
            }
        }

        private void stopTime(bool hasInvoke) {
            // 停止定时任务
            tmr.Stop();
            if (hasInvoke)
            {
                this.Invoke(new Action(() =>
                {
                    this.but_start_sendData.Enabled = true;
                    this.but_stop_sendData.Enabled = false;
                }));
            }
            else {
                this.but_start_sendData.Enabled = true;
                this.but_stop_sendData.Enabled = false;
            }
        }
    }
}
